
cc.Class({
    extends: cc.Component,

    properties: {
        grid: {
            default: null,
            type: cc.SpriteFrame
        },
        grid_small: {
            default: null,
            type: cc.SpriteFrame
        },
        next: {
            default: null,
            type: cc.Node
        },
        gameOverMenu: {
            default: null,
            type: cc.Node
        },
        clearVol: {
            default: null,
            type: cc.AudioClip
        },
        lines: {
            default: null,
            type: cc.Node
        },
        gridSize: 70,
        shape: [],
        mapData: [],
        nextData: [],
        shapeIndex: 0,
        stateIndex: 0,
        currentShape: 0,
        nextShapeIndex: 0,
        nextStateIndex: 0,
        nextShape: 0,
        x: 0,
        y: 3,
        points: 0,
        isOver: false,
        time: 1000,
        autoD: null
    },

    random(min, max){
        return Math.floor(Math.random() * (max - min + 1)) + min
    },

    traversal(target, fn){
        for(let i=0; i<target.length; i++){
            for(let n=0; n<target[i].length; n++){
                fn(target[i][n], i, n)
            }
        }
    },

    checkCollision(shape, newX, newY){
        let result = true
        this.traversal(shape, function(ele, x, y){
            if(ele){
                !this.mapData[x + newX] ||
                !this.mapData[x + newX][y + newY] ||
                this.mapData[x + newX][y + newY].isOccupy ?
                result = false : result
            }
        }.bind(this))
        return result
    },

    autoDown(){
        this.autoD = setInterval(this.down.bind(this), this.time)
    },

    down(p){
        if(this.checkCollision(this.currentShape, this.x+1, this.y)){
            this.clearShape()
            this.x += 1
            this.fillShape()
            if(p){
                this.down(p)
            }
        }
        else{
            this.downed()
        }
    },

    downed(){
        this.traversal(this.currentShape, function(ele, x, y){
            if(ele){
                this.mapData[this.x + x][this.y + y].isOccupy = true
            }
        }.bind(this))
        this.checkOver()
        this.checkLine()
    },

    checkLine(){
        let lines = []
        let isFull = null
        for(let i=0; i<this.currentShape.length; i++){
            isFull = true
            for(let n=0; n<this.mapData[i+this.x].length; n++){
                if(!this.mapData[i+this.x][n].isOccupy){
                    isFull = false
                    break
                }
            }
            if(isFull){
                lines.push(i+this.x)
            }
        }
        if(lines.length){
            this.clearLine(lines)
        }
        else{
            this.continue()
        }
    },

    clearLine(lines){
        cc.audioEngine.play(this.clearVol, false, 1)
        for(let i=0; i<lines.length; i++){
            for(let n=0; n<this.mapData[lines[i]].length; n++){
                this.mapData[lines[i]][n].spriteFrame = null
                this.mapData[lines[i]][n].isOccupy = false
            }
        }
        this.points += lines.length
        this.lines.string = this.points
        this.sink(lines)
    },

    sink(lines){
        for(let m=0; m<lines.length; m++){

            for(let i=lines[m]-1; i>0; i--){
                for(let n=0; n<this.mapData[i].length; n++){
                    this.mapData[i+1][n].spriteFrame = this.mapData[i][n].spriteFrame
                    this.mapData[i+1][n].isOccupy = this.mapData[i][n].isOccupy
                    this.mapData[i][n].spriteFrame = null
                    this.mapData[i][n].isOccupy = false
                }
            }
        }
        this.continue()
    },

    continue(){
        
        this.shapeIndex = this.nextShapeIndex
        this.stateIndex = this.nextStateIndex
        this.currentShape = this.shape[this.shapeIndex][this.stateIndex]
        this.x = 0
        this.y = 3
        this.fillShape()
        
        this.clearNext()
        this.getNextShape()
        this.fillNext()
    },

    rotate(){
        let stateIndex = this.stateIndex < this.shape[this.shapeIndex].length - 1 ? this.stateIndex + 1 : 0
        if(this.checkCollision(this.shape[this.shapeIndex][stateIndex], this.x, this.y)){
            this.clearShape()
            this.stateIndex = stateIndex
            this.currentShape = this.shape[this.shapeIndex][stateIndex]
            this.fillShape()
        }
    },

    left(){
        if(this.checkCollision(this.currentShape, this.x, this.y-1)){
            this.clearShape()
            this.y -= 1
            this.fillShape()
        }
    },

    right(){
        if(this.checkCollision(this.currentShape, this.x, this.y+1)){
            this.clearShape()
            this.y += 1
            this.fillShape()
        }
    },

    fillGrid(x, y){
        this.mapData[x][y].spriteFrame = this.grid
    },

    clearGrid(x, y){
        this.mapData[x][y].spriteFrame = null
    },

    fillNext(){
        this.traversal(this.nextShape, function(ele, x, y){
            if(ele){
                this.nextData[x][y].spriteFrame = this.grid_small
            }
        }.bind(this))
    },

    clearNext(){
        this.traversal(this.nextShape, function(ele, x, y){
            if(ele){
                this.nextData[x][y].spriteFrame = null
            }
        }.bind(this))
    },

    clearShape(){
        this.traversal(this.currentShape, function(ele, x, y){
            if(ele){
                this.clearGrid(this.x + x, this.y + y)
            }
        }.bind(this))
    },

    fillShape(){
        this.traversal(this.currentShape, function(ele, x, y){
            if(ele){
                this.fillGrid(this.x + x, this.y + y)
            }
        }.bind(this))
    },

    checkOver(){
        for(let i=0; i<this.mapData[0].length; i++){
            if(this.mapData[0][i].isOccupy){
                this.isOver = true
                break
            }
        }
        if(this.isOver){
            this.gameover()
        }
    },

    gameover(){
        clearInterval(this.autoD)
        this.gameOverMenu.active = true
    },

    initial(){
        let node = null
        let sprite = null

        // 初始化主地图
        for(let row=0,y=-this.gridSize; row<20; row++, y-=this.gridSize){
            this.mapData[row] = []
            for(let col=0, x=0; col<10; col++, x+=this.gridSize){
                node = new cc.Node()
                sprite = node.addComponent(cc.Sprite)
                sprite.sizeMode = cc.Sprite.SizeMode.CUSTOM
                sprite.trim = false
                sprite.isOccupy = false
                node.width = this.gridSize
                node.height = this.gridSize
                node.anchorX = 0
                node.anchorY = 0
                node.x = x
                node.y = y
                this.mapData[row][col] = sprite
                node.parent = this.node
            }
        }

        // 初始化下一个提示地图
        for(let row=0, y=-40; row<4; row++, y-=40){
            this.nextData[row] = []
            for(let col=0,x=0; col<4; col++,x+=40){
                node = new cc.Node()
                sprite = node.addComponent(cc.Sprite)
                sprite.sizeMode = cc.Sprite.SizeMode.CUSTOM
                sprite.trim = false
                node.width = 40
                node.height = 40
                node.anchorX = 0
                node.anchorY = 0
                node.x = x
                node.y = y
                this.nextData[row][col] = sprite
                node.parent = this.next
            }
        }

        this.shape = [
            [
                [
                    [0, 1, 0],
                    [1, 1, 0],
                    [0, 1, 0]
                ],
                [
                    [0, 1, 0],
                    [1, 1, 1]
                ],
                [
                    [0, 1, 0],
                    [0, 1, 1],
                    [0, 1, 0]
                ],
                [
                    [0, 0, 0],
                    [1, 1, 1],
                    [0, 1, 0]
                ]
            ],
            [
                [
                    [1, 1, 0],
                    [0, 1, 0],
                    [0, 1, 0]
                ],
                [
                    [0, 0, 1],
                    [1, 1, 1]
                ],
                [
                    [0, 1, 0],
                    [0, 1, 0],
                    [0, 1, 1]
                ],
                [
                    [0, 0, 0],
                    [1, 1, 1],
                    [1, 0, 0]
                ]
            ],
            [
                [
                    [0, 1, 0],
                    [0, 1, 0],
                    [1, 1, 0]
                ],
                [
                    [1, 0, 0],
                    [1, 1, 1]
                ],
                [
                    [0, 1, 1],
                    [0, 1, 0],
                    [0, 1, 0]
                ],
                [
                    [0, 0, 0],
                    [1, 1, 1],
                    [0, 0, 1]
                ]
            ],
            [
                [
                    [1, 1, 0],
                    [0, 1, 1]
                ],
                [
                    [0, 0, 1],
                    [0, 1, 1],
                    [0, 1, 0]
                ]
            ],
            [
                [
                    [0, 1, 1],
                    [1, 1, 0]
                ],
                [
                    [1, 0, 0],
                    [1, 1, 0],
                    [0, 1, 0]
                ]
            ],
            [
                [
                    [1, 1],
                    [1, 1]
                ]
            ],
            [
                [
                    [0, 1],
                    [0, 1],
                    [0, 1],
                    [0, 1]
                ],
                [
                    [0, 0, 0, 0],
                    [1, 1, 1, 1]
                ]
            ]
        ]
        this.getShape()
        this.getNextShape()
    },

    getShape(){
        this.shapeIndex = this.random(0, 6)
        switch(this.shapeIndex){
            case 0:
            case 1:
            case 2:
            case 6:
            this.stateIndex = this.random(0, this.shape[this.shapeIndex].length - 2)
        }
        this.currentShape = this.shape[this.shapeIndex][this.stateIndex]
    },

    getNextShape(){
        this.nextShapeIndex = this.random(0, 6)
        switch(this.shapeIndex){
            case 0:
            case 1:
            case 2:
            case 6:
            this.nextStateIndex = this.random(0, this.shape[this.nextShapeIndex].length - 2)
        }
        this.nextShape = this.shape[this.nextShapeIndex][this.nextStateIndex]
    },

    onLoad () {
        this.lines = this.lines.getComponent(cc.Label)
        this.initial()
    },

    start () {
        this.fillShape()
        this.fillNext()
        this.autoDown()
    },

    // update (dt) {},
});
